<template>
    <view class="waterfall-components" :style="[waterfallStyle]">
        <scroll-list ref="list" @load="load" @refresh="refresh" :option="option">
            <view class="waterfall-list-wrap" :style="[waterfallListStyle]">
                <view class="waterfall-list" id="waterfall-list__left" :style="[waterfallLeftStyle]">
                    <view v-for="(item, index) in leftList" :key="index">
                        <slot name="left" :entity="item" :index="index" :column="column"></slot>
                    </view>
                </view>
                <view class="waterfall-list" id="waterfall-list__right" v-if="column > 1">
                    <view v-for="(item, index) in rightList" :key="index">
                        <slot name="right" :entity="item" :index="index" :column="column"></slot>
                    </view>
                </view>
            </view>
        </scroll-list>
    </view>
</template>

<script>
/**
 * waterfall 瀑布流组件
 * @description 瀑布流组件一般用于展示商品列表
 */
export default {
    name: 'waterfall',
    props: {
        // 列表数据
        list: {
            type: Array,
            default: () => []
        },
        option: {
            type: Object,
            default: () => ({
                size: 15,
            })
        },
        // 模式 1-简单左右分组，按顺序排列，伪瀑布流 2-计算左右容器高度进行分组
        mode: {
            type: [String, Number],
            default: 2
        },
        // 列数 最大2列
        column: {
            type: [String, Number],
            default: 2
        },
        //列与列的间隙
        columnGap: {
            type: [String, Number],
            default: 10
        },
        //左侧和列表的间隙
        leftGap: {
            type: [String, Number],
            default: 20
        },
        //右侧和列表的间隙
        rightGap: {
            type: [String, Number],
            default: 20
        },
        //列表背景色，可使用渐变色
        backgroundColor: {
            type: String,
            default: 'transparent'
        },
        //列表外层容器圆角值
        radius: {
            type: [String, Number],
            default: 0
        }
    },
    data() {
        return {
            leftListConst: [],
            leftList: [],
            rightList: []
        };
    },
    watch: {
        list(val) {
        	this.handleColumnChange();
        },
        // 监听列数改变
    	column(val) {
    		this.handleColumnChange(val);
    	}
    },
    methods: {
        // 列数切换
        handleColumnChange(val){
            if (this.column < 2) {
            	this.leftList = [...this.list];
            } else {
            	if (val && val == 2) {
            		this.leftList = [...this.leftListConst]
            	}
            	this.handleInitData()
            }
        },
        // 初始化数据
        handleInitData() {
        	if (this.mode == 1) {
        		this.handleGetSubGroup();
        	} else {
        		this.handleGetArrayByHeight();
        	}
        },
        handleGetDiffList() {
        	let diffList = [];
        	let total = this.list.length;
        	if (total <= this.option.size) {
        		this.leftListConst = [];
        		this.leftList = [];
        		this.rightList = [];
        	}
        	let sum = this.leftListConst.length + this.rightList.length;
        	let diff = total - sum;
        	if (diff > 0) {
        		diffList = [...this.list].filter((item, index) => {
        			return index >= sum;
        		});
        	}
        	return diffList;
        },
        handleGetSubGroup() {
        	//type=1时执行简单数据分组
        	if (!this.list && this.list.length === 0) return;
        	let leftList = [];
        	let rightList = [];
        	let data = this.handleGetDiffList();
        	data.forEach((item, index) => {
        		if (index % 2 === 0) {
        			leftList.push(item);
        		} else {
        			rightList.push(item);
        		}
        	});
        	this.leftList = this.leftList.concat(leftList);
        	this.leftListConst = this.leftListConst.concat(leftList);
        	this.rightList = this.rightList.concat(rightList);
        },
        async handleGetArrayByHeight() {
        	if (!this.list && this.list.length === 0) return;
        	let data = this.handleGetDiffList();
        	for (let item of data) {
        		await this.handleRender(item);
        	}
        },
        async handleRender(item) {
        	let obj = await this.handleGetContainerHeight();
        	return await new Promise((resolve, reject) => {
        		if (obj && typeof obj.leftHeight === 'number') {
        			if (obj.leftHeight <= obj.rightHeight) {
        				this.leftList.push(item);
        				this.leftListConst.push(item);
        			} else {
        				this.rightList.push(item);
        			}
        			this.$nextTick(() => {
        				setTimeout(() => {
        					resolve(true);
        				}, 50);
        			});
        		} else {
        			reject(false);
        		}
        	});
        },
        async handleGetContainerHeight() {
        	//mode=2
        	return await new Promise((resolve, reject) => {
        		const query = uni.createSelectorQuery().in(this);
        		let nodes = query.selectAll('#waterfall-list__left, #waterfall-list__right');
        		nodes.boundingClientRect().exec(res => {
        			if (res && res[0]) {
        				const rects = res[0];
        				const leftHeight = rects[0].height;
        				const rightHeight = rects[1].height;
        				resolve({
        					leftHeight: leftHeight,
        					rightHeight: rightHeight
        				});
        			} else {
        				reject(res);
        			}
        		});
        	});
        },
        // 数据加载
        load(paging) {
            this.$emit('load',paging);
        },
        // 加载成功 调用scroll-list的方法
        loadSuccess(data){
            this.$refs.list.loadSuccess(data);
        },
        // 加载失败 调用scroll-list的方法
        loadFail(data){
            this.$refs.list.loadFail(data);
        },
        // 数据刷新
        refresh(paging) {
            this.$emit('refresh',paging);
        },
        // 刷新成功 调用scroll-list的方法
        refreshSuccess(data){
            this.$refs.list.refreshSuccess(data);
        },
        // 刷新失败 调用scroll-list的方法
        refreshFail(data){
            this.$refs.list.refreshFail(data);
        },
        // 数字转换rpx
        transRpx(val) {
            return /[rpx]/.test(val) ? val : `${val}rpx`;
        }
    },
    mounted() {
        this.handleColumnChange();
    },
    computed: {
        waterfallStyle() {
            const style = {};
            style.background = this.backgroundColor;
            return style;
        },
        waterfallListStyle() {
            const style = {};
            style.paddingLeft = this.transRpx(this.leftGap);
            style.paddingRight = this.transRpx(this.rightGap);
            style.borderRadius = this.transRpx(this.radius);
            return style;
        },
        waterfallLeftStyle() {
            const style = {};
            style.marginRight = this.transRpx(this.columnGap);
            return style;
        }

    }
};
</script>

<style scoped lang="scss">
.waterfall-components {
    .waterfall-list-wrap {
        width: 100%;
        flex-wrap: wrap;
        display: inline-flex;
        flex-direction: row;
        align-items: flex-start;
        justify-content: space-between;
        .waterfall-list {
            flex: 1;
        }
    }
}
</style>
